package com.group.itms.routes.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.sax.StartElementListener;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.group.itms.routes.R;
import com.group.itms.routes.activities.InformationPointActivity;
import com.group.itms.routes.data.ObjectType;
import com.group.itms.routes.map.Layer.Type;
import com.group.itms.routes.utils.LocationService;

public class GoogleMapWrapper implements Map {

	public static final int MY_LOCATION_LAYER_ID = -17;

	private Context mContext;
	private LayersChangedListener mLayersChangedListener;
	private GoogleMap mMap;
	private List<Layer> mLayers;
	private LocationService mLocationService;
	private Bounds mBounds;

	private HashMap<String, Marker> markerObject;

	float mZoom = 12;

	public GoogleMapWrapper(Context cntx) {
		mContext = cntx;
		mLayers = new ArrayList<Layer>();
		mLocationService = new LocationService(cntx);
		markerObject = new HashMap<String, Marker>();
		setLayersChangedListener();
	}

	public Bounds getBounds() {
		return mBounds;
	}

	public void setBounds(Bounds mBounds) {
		this.mBounds = mBounds;
	}

	public void setMapType(MapType type) {
		switch (type) {
		case Hybrid:
			mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
			break;
		case Stallite:
			mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
			break;
		case Normal:
			mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
			break;
		case Terrain:
			mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
			break;
		}
	}

	@Override
	public void setZoom(float zoom) {
		mZoom = zoom;
	}

	@Override
	public void setMapInternal(Object map) {
		mMap = (GoogleMap) map;
		mMap.setOnCameraChangeListener(new OnCameraChangeListener() {

			@Override
			public void onCameraChange(CameraPosition position) {
				mZoom = position.zoom;
			}
		});

		mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {

			@Override
			public void onInfoWindowClick(
					com.google.android.gms.maps.model.Marker marker) {

				Marker m = markerObject.get(marker.getId());
				if (m.getObject().getType().equals(ObjectType.INF_POINT)) {
					Intent intent = new Intent(InformationPointActivity
							.getIntent(mContext, m.getObject().getId()));
					mContext.startActivity(intent);
				} else if (m.getObject().getType().equals(ObjectType.TASK)) {
					new AlertDialog.Builder(mContext)
							.setTitle(marker.getTitle())
							.setMessage(marker.getSnippet())
							.setPositiveButton("Ok", new OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog,
										int which) {
									return;
								}
							}).create().show();
				}

			}
		});

		UiSettings setting = mMap.getUiSettings();
		setting.setMyLocationButtonEnabled(true);
	}

	@Override
	public void setMyLocation() {
		Location loc = mLocationService.getCurrentLocation();
		Layer layer = null;
		for (Layer l : mLayers) {
			if (l.getId() == MY_LOCATION_LAYER_ID)
				layer = l;
		}
		if (layer == null) {
			layer = new Layer();
			layer.setId(MY_LOCATION_LAYER_ID);
			layer.setVisible(true);
			mLayers.add(layer);
		}
		addMarker(loc.getLatitude(), loc.getLongitude(), -1, layer);
	}

	@Override
	public IMarker addMarker(double x, double y, int icId, Layer layer) {
		Marker marker = new Marker();
		marker.setInfoText("");
		PointD point = new PointD(x, y);

		marker.setLocation(point);

		if (mLayers != null) {
			for (Layer l : mLayers) {
				if (l.equals(layer)) {
					l.addMarker(marker);
					LayerChanged(l);
				}
			}
		}

		return marker;
	}

	@Override
	public void goToMyLocation() {
		Location myLoc = mLocationService.getCurrentLocation();
		LatLng latlng = new LatLng(myLoc.getLatitude(), myLoc.getLongitude());
		mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng, mZoom));
	}

	@Override
	public void addLayers(List<Layer> layers) {
		for (Layer l : layers) {
			mLayers.add(l);
		}
		ListChanged(mLayers);
	}

	@Override
	public void goToRoutes() {
		double centerX = (mBounds.getRightUpX() + mBounds.getLeftDowonX()) / 2;
		double centerY = (mBounds.getRightUpY() + mBounds.getLeftDowonY()) / 2;
		LatLng latlng = new LatLng(centerY, centerX);
		mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng, mZoom));
	}

	@Override
	public void traceMyLocation(boolean yesNo, int period) {

	}

	@Override
	public void setLayersChangedListener() {
		mLayersChangedListener = new LayersChangedListener() {

			@Override
			public void OnLayerListChanged(List<Layer> layers) {
				reDraw();
			}

			@Override
			public void OnLayerChanged(Layer layer) {
				reDraw();
			}
		};
	}

	@Override
	public void drawOnMap() {
		if (mMap == null) {
			return;
		}
		for (Layer layer : mLayers) {
			if (layer.isVisible()) {
				if (layer.getType() == Type.POINT)
					drawInfoPointsLayer(layer);
				if (layer.getType() == Type.TASK)
					drawTaskLayer(layer);
				if (layer.getType() == Type.ROUTE)
					drawRoutesLayer(layer);
				// if(layer.getType() == null)
				// drawMyLocationLayer(layer);
			}

		}
		goToRoutes();
		drawBounds();
	}

	private void drawInfoPointsLayer(Layer layer) {
		for (Marker marker : layer.getMarkers()) {
			MarkerOptions mo = new MarkerOptions();
			mo.snippet(marker.getObject().getText());
			mo.title("Information Point : " + marker.getObject().getName());
			mo.icon(BitmapDescriptorFactory
					.fromResource(R.drawable.ic_information));
			mo.position(new LatLng(marker.getY(), marker.getX()));
			markerObject.put(mMap.addMarker(mo).getId(), marker);
		}
	}

	private void drawRoutesLayer(Layer layer) {
		PolylineOptions opt = new PolylineOptions();
		for (Marker marker : layer.getMarkers()) {
			opt.add(new LatLng(marker.getY(), marker.getX()));
		}
		mMap.addPolyline(opt);
	}

	@SuppressWarnings("unused")
	private void drawMyLocationLayer(Layer layer) {
		for (Marker marker : layer.getMarkers()) {
			MarkerOptions mo = new MarkerOptions();
			mo.snippet(marker.getInfoText());
			mo.title("My Location");
			mo.icon(BitmapDescriptorFactory.defaultMarker());
			mo.position(new LatLng(marker.getX(), marker.getY()));
			mMap.addMarker(mo);
		}
	}

	private void drawTaskLayer(Layer layer) {
		for (Marker marker : layer.getMarkers()) {
			MarkerOptions mo = new MarkerOptions();
			mo.snippet(marker.getObject().getText());
			mo.title("Field Task");
			mo.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_task));
			mo.position(new LatLng(marker.getY(), marker.getX()));
			markerObject.put(mMap.addMarker(mo).getId(), marker);
		}
	}

	private void drawBounds() {
		PolygonOptions op = new PolygonOptions();
		op.strokeColor(Color.RED);
		op.strokeWidth(3);
		LatLng first = new LatLng(mBounds.getLeftDowonY(),mBounds.getLeftDowonX());
		LatLng second = new LatLng(mBounds.getRightUpY(), mBounds.getLeftDowonX());
		LatLng third = new LatLng(mBounds.getRightUpY(), mBounds.getRightUpX());
		LatLng fourth = new LatLng(mBounds.getLeftDowonY(), mBounds.getRightUpX());
		op.add(first,second,third,fourth);
		mMap.addPolygon(op);
	}

	@Override
	public void clearMap() {
		if (mMap != null) {
			mMap.clear();
		}
	}

	@Override
	public LayersChangedListener getLayersChangedListener() {
		return mLayersChangedListener;
	}

	@Override
	public void removeLayer(Layer layer) {
		mLayers.remove(layer);
		ListChanged(mLayers);
	}

	@Override
	public void addLayer(Layer layer) {
		mLayers.add(layer);
		ListChanged(mLayers);
	}

	@Override
	public void setLayerVisibility(Layer layer, boolean visibility) {
		for (Layer l : mLayers) {
			if (l.equals(layer)) {
				l.setVisible(visibility);
				LayerChanged(l);
			}
		}
	}

	@Override
	public void setLayerTypeVisibility(Type type, boolean visible) {
		for (Layer l : mLayers) {
			if (l.getType() == type) {
				l.setVisible(visible);
			}
		}
		ListChanged(mLayers);
	}

	@Override
	public void removeAllLayer() {
		mLayers.clear();
		ListChanged(mLayers);
	}

	@Override
	public void reDraw() {
		clearMap();
		drawOnMap();
	}

	void ListChanged(List<Layer> list) {
		if (mLayersChangedListener != null) {
			mLayersChangedListener.OnLayerListChanged(list);
		}
	}

	void LayerChanged(Layer layer) {
		if (mLayersChangedListener != null) {
			mLayersChangedListener.OnLayerChanged(layer);
		}
	}
}
